/* lco: a coroutine library for C that minimalises stack usage
   Copyright (C) 2018 lco author

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

.text
.global _lco_switch
.global _lco_call

/* I do not have much experience with x86-64 assembly, it might be optimisable. */
_lco_switch:
        /* %rdi: void *next_sp, %rsi: void **current_sp */
	/* Function prologue */
	sub $64,%rsp
        /* Save callee-saved registers */
        movq %rbx, (%rsp)
        /* Save the stack pointer in *current_sp */
        /* movq %rsp, 8(%rsp) */
        movq %rsp, (%rsi)
        movq %rbp, 8(%rsp)
        movq %r12, 16(%rsp)
        movq %r13, 24(%rsp)
        movq %r14, 32(%rsp)
        movq %r15, 40(%rsp)
        /* TODO: there is some padding (reduce stack usage) */
        /* save x87 control word (XXX exceptions) */
        fnstcw 48(%rsp)
        /* save status bits of mxcsr */
        stmxcsr 56(%rsp)
	/* ret is used to switch to the caller */
        /* Everything except the stack pointer has been saved. */
        /* Resume the other coroutine by changing the stack. */
        movq %rdi, %rsp

/* Restore the registers, once we are in a different coroutine or OS thread. */
/* _lco_switch_continue: */
        /* Registers: %rsp: the stack, with saved registers */
        /* Restore callee-saved registers */
        movq (%rsp), %rbx
        movq 8(%rsp), %rbp
        movq 16(%rsp), %r12
        movq 24(%rsp), %r13
        movq 32(%rsp), %r14
        movq 40(%rsp), %r15
        /* Load x87 control word (XXX exceptions) */
        fldcw 48(%rsp)
        /* Load status bits of mxcsr */
        ldmxcsr 56(%rsp)
	/* Function epilogue */
	add $64,%rsp
	/* TODO: retpoline, Spectre */
	retq

_lco_call:
	/* Registers: %rbx: co */
	movq %rbx, %rdi
	/* co->entry is the first field */
	jmpq *(%rbx)
